﻿#region Copyright (C) Sector7 Software Studio. All rights reserved
/*******************************************************************************************
 * Creation
 *      Author:         Wolf Lai
 *      Date:           2011/10/27 21:48:20
 *      Version:        1.0.1101
 * Modification 
 *      Author: 
 *      Date: 
 *      Description: 
 *      Version:
 *******************************************************************************************/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using Sector7.Framework.Core;
using Sector7.Framework.Enums;
using Sector7.Framework.Consts;

namespace Sector7.Framework.Utility
{
    /// <summary>
    /// 反射工具类
    /// </summary>
    public class ReflectionUtil
    {
        #region Public functions
        /// <summary>
        /// 获取动态库中指定类型声明
        /// </summary>
        /// <param name="dllFileName">动态库全名（包含路径）</param>
        /// <param name="className">类全名</param>
        /// <returns></returns>
        public static Type GetType(string dllFileName, string className)
        {
            Assembly assembly = LoadAssembly(dllFileName);

            return assembly.GetType(className, false, true);
        }

        /// <summary>
        /// 创建类实例
        /// </summary>
        /// <param name="type">类类型</param>
        /// <param name="args">构造参数</param>
        /// <returns>类实例</returns>
        public static object CreateInstance(Type type, params object[] args)
        {
            object obj = Activator.CreateInstance(type, args);

            return obj;
        }

        /// <summary>
        /// 创建类实例
        /// </summary>
        /// <param name="className">类全名</param>
        /// <param name="args">构造参数</param>
        /// <returns>类实例</returns>
        public static object CreateInstance(string className, params object[] args)
        {
            //object obj = Activator.CreateInstance(Type.GetType(className), args);
            object obj = ApplicationUtil.GetEntryAssembly().CreateInstance(className, true, BindingFlags.CreateInstance, null, args, null, null);
            return obj;
        }

        /// <summary>
        /// 创建类实例
        /// </summary>
        /// <param name="dllFileName">动态库全名（包含路径）</param>
        /// <param name="className">类全名</param>
        /// <param name="args">构造参数</param>
        /// <returns>类实例</returns>
        public static object CreateInstance(string dllFileName, string className, params object[] args)
        {
            Assembly assembly = LoadAssembly(dllFileName);
            object obj = assembly.CreateInstance(className, false, BindingFlags.CreateInstance, null, args, null, null);

            return obj;
        }

        /// <summary>
        /// 创建泛型类实例
        /// </summary>
        /// <param name="dllFileName">动态库全名（包含路径）</param>
        /// <param name="className">类全名</param>
        /// <returns></returns>
        public static object CreateGenericInstance(string dllFileName, string className)
        {
            return null;
        }

        /// <summary>
        /// 复制源对象属性至目标对象
        /// </summary>
        /// <param name="source">源对象</param>
        /// <param name="target">目标对象</param>
        /// <param name="excludeTypes">排除复制的类型</param>
        public static void CopyTo(object source, ref object target, params Type[] excludeTypes)
        {
            try
            {
                string propertyName;
                object propertyValue;
                foreach (PropertyInfo property in GetProperties(source))
                {
                    propertyName = property.Name;
                    propertyValue = property.GetValue(source, null);
                    if (HasProperty(target, propertyName))
                    {
                        PropertyInfo __property = GetProperty(target, propertyName);
                        if (excludeTypes.Length > 0 && !excludeTypes.Contains(__property.PropertyType))
                            __property.SetValue(target, propertyValue, null);
                    }
                }
            }
            catch (Exception e)
            {
                Log.WriteLine(LogSeverityType.ERR, C_ModuleName.FRAMEWORK, e);
                throw e;
            }
        }

        /// <summary>
        /// 复制源对象属性至目标对象
        /// </summary>
        /// <param name="source">源对象</param>
        /// <param name="target">目标对象</param>
        public static void CopyTo(object source, ref object target)
        {
            try
            {
                string propertyName;
                object propertyValue;
                foreach (PropertyInfo property in GetProperties(source))
                {
                    propertyName = property.Name;
                    propertyValue = property.GetValue(source, null);
                    if (HasProperty(target, propertyName))
                    {
                        GetProperty(target, propertyName).SetValue(target, propertyValue, null);
                    }
                }
            }
            catch (Exception e)
            {
                Log.WriteLine(LogSeverityType.ERR, C_ModuleName.FRAMEWORK, e);
                throw e;
            }
        }

        /// <summary>
        /// 复制源对象属性至目标对象
        /// </summary>
        /// <param name="source">源对象</param>
        /// <param name="target">目标对象</param>
        public static void CopyTo(object source, object target)
        {
            try
            {
                string propertyName;
                object propertyValue;
                foreach (PropertyInfo property in GetProperties(source))
                {
                    propertyName = property.Name;
                    propertyValue = property.GetValue(source, null);
                    if (HasProperty(target, propertyName))
                    {
                        GetProperty(target, propertyName).SetValue(target, propertyValue, null);
                    }
                }
            }
            catch (Exception e)
            {
                Log.WriteLine(LogSeverityType.ERR, C_ModuleName.FRAMEWORK, e);
                throw e;
            }
        }

        /// <summary>
        /// 调用某数据对象方法
        /// </summary>
        /// <param name="obj">数据对象</param>
        /// <param name="methodName">方法名</param>
        /// <param name="args">方法参数列表</param>
        /// <returns></returns>
        public static object InvokeMethod(object obj, string methodName, params object[] args)
        {
            object ret = InvokeMethod(obj.GetType(), methodName, obj, args);

            return ret;
        }

        /// <summary>
        /// 调用方法
        /// </summary>
        /// <param name="type">类型声明</param>
        /// <param name="methodName">方法名</param>
        /// <param name="target">被调用指定成员对象</param>
        /// <param name="args">方法参数列表</param>
        /// <returns>方法返回值</returns>
        public static object InvokeMethod(Type type, string methodName, object target, params object[] args)
        {
            object ret = type.InvokeMember(methodName, BindingFlags.InvokeMethod, null, target, args);

            return ret;
        }

        /// <summary>
        /// 调用方法
        /// </summary>
        /// <param name="dllFileName">动态库全名（包含路径）</param>
        /// <param name="className">类全名</param>
        /// <param name="methodName">方法名</param>
        /// <param name="target">被调用指定成员对象</param>
        /// <param name="args">方法参数列表</param>
        /// <returns>方法返回值</returns>
        public static object InvokeMethod(string dllFileName, string className, string methodName, object target, params object[] args)
        {
            Type type = GetType(dllFileName, className);

            object ret = type.InvokeMember(methodName, BindingFlags.InvokeMethod, null, target, args);

            return ret;
        }

        /// <summary>
        /// 调用非公共方法
        /// </summary>
        /// <param name="obj">数据对象</param>
        /// <param name="methodName">方法名</param>
        /// <param name="args">方法参数列表</param>
        /// <returns></returns>
        public static object InvokePrivateMethod(object obj, string methodName, params object[] args)
        {
            object ret = InvokePrivateMethod(obj.GetType(), methodName, obj, args);

            return ret;
        }

        /// <summary>
        /// 调用非公共方法
        /// </summary>
        /// <param name="type">类型声明</param>
        /// <param name="methodName">方法名</param>
        /// <param name="target">被调用指定成员对象</param>
        /// <param name="args">方法参数列表</param>
        /// <returns></returns>
        public static object InvokePrivateMethod(Type type, string methodName, object target, params object[] args)
        {
            object ret = type.InvokeMember(methodName, BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, target, args);

            return ret;
        }

        /// <summary>
        /// 调用静态方法
        /// </summary>
        /// <param name="dllFileName">动态库全名（包含路径）</param>
        /// <param name="className">类全名</param>
        /// <param name="methodName">方法名</param>
        /// <param name="args">方法参数列表</param>
        /// <returns>方法返回值</returns>
        public static object InvokeStaticMethod(string dllFileName, string className, string methodName, params object[] args)
        {
            try
            {
                Type type = GetType(dllFileName, className);

                object ret = InvokeStaticMethod(type, methodName, args);

                return ret;
            }
            catch (Exception e)
            {
                Log.WriteLine(LogSeverityType.ERR, C_ModuleName.FRAMEWORK, e);
                throw e;
            }
        }

        /// <summary>
        /// 调用静态方法
        /// </summary>
        /// <param name="dllFileName">动态库全名（包含路径）</param>
        /// <param name="className">类全名</param>
        /// <param name="methodName">方法名</param>
        /// <param name="argsTypes">参数类型数组</param>
        /// <param name="args">方法参数列表</param>
        /// <returns>方法返回值</returns>
        public static object InvokeStaticMethod(string dllFileName, string className, string methodName, Type[] argsTypes, params object[] args)
        {
            try
            {
                Type type = GetType(dllFileName, className);

                object ret = InvokeStaticMethod(type, methodName, argsTypes, args);

                return ret;
            }
            catch (Exception e)
            {
                Log.WriteLine(LogSeverityType.ERR, C_ModuleName.FRAMEWORK, e);
                throw e;
            }
        }

        /// <summary>
        /// 调用静态方法
        /// </summary>
        /// <param name="type">类型声明</param>
        /// <param name="methodName">方法名</param>
        /// <param name="args">方法参数列表</param>
        /// <returns>方法返回值</returns>
        public static object InvokeStaticMethod(Type type, string methodName, params object[] args)
        {
            try
            {
                MethodInfo method = type.GetMethod(methodName);

                object ret = method.Invoke(null, args);

                return ret;
            }
            catch (Exception e)
            {
                Log.WriteLine(LogSeverityType.ERR, C_ModuleName.FRAMEWORK, e);
                throw e;
            }
        }

        /// <summary>
        /// 调用静态方法
        /// </summary>
        /// <param name="type">类型声明</param>
        /// <param name="methodName">方法名</param>
        /// <param name="argsTypes">参数类型数组</param>
        /// <param name="args">方法参数列表</param>
        /// <returns>方法返回值</returns>
        public static object InvokeStaticMethod(Type type, string methodName, Type[] argsTypes, params object[] args)
        {
            try
            {
                MethodInfo method = type.GetMethod(methodName, argsTypes);

                object ret = method.Invoke(null, args);

                return ret;
            }
            catch (Exception e)
            {
                Log.WriteLine(LogSeverityType.ERR, C_ModuleName.FRAMEWORK, e);
                throw e;
            }
        }

        /// <summary>
        /// 判断某对象是否包含指定方法
        /// </summary>
        /// <param name="obj">数据对象</param>
        /// <param name="methodName">方法名</param>
        /// <param name="argTypes">参数类型</param>
        /// <returns></returns>
        public static bool HasMethod(object obj, string methodName, params Type[] argTypes)
        {
            return obj.GetType().GetMethod(methodName, argTypes) != null;
        }

        /// <summary>
        /// 获取某类型指定标志的方法
        /// </summary>
        /// <param name="type"></param>
        /// <param name="flags"></param>
        /// <returns></returns>
        public static MethodInfo[] GetMethods(Type type, BindingFlags flags)
        {
            return type.GetMethods(flags);
        }

        /// <summary>
        /// 判断某对象是否包含指定属性
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="propertyName"></param>
        /// <returns></returns>
        public static bool HasProperty(object obj, string propertyName)
        {
            return obj.GetType().GetProperty(propertyName) != null;
        }

        /// <summary>
        /// 获取某对象指定属性
        /// </summary>
        /// <param name="obj">数据对象</param>
        /// <param name="propertyName">属性名</param>
        /// <returns></returns>
        public static PropertyInfo GetProperty(object obj, string propertyName)
        {
            PropertyInfo property = null;

            try
            {
                Type type = obj.GetType();
                property = type.GetProperty(propertyName);
            }
            catch (Exception e)
            {
                Log.WriteLine(LogSeverityType.ERR, C_ModuleName.FRAMEWORK, e);
                throw e;
            }

            return property;
        }

        /// <summary>
        /// 获取某对象指定属性值
        /// </summary>
        /// <param name="obj">数据对象</param>
        /// <param name="propertyName">属性名</param>
        /// <returns></returns>
        public static object GetPropertyValue(object obj, string propertyName)
        {
            object value = null;

            try
            {
                PropertyInfo property = GetProperty(obj, propertyName);
                if (property != null)
                    value = property.GetValue(obj, null);
            }
            catch (Exception e)
            {
                Log.WriteLine(LogSeverityType.ERR, C_ModuleName.FRAMEWORK, e);
                throw e;
            }

            return value;
        }

        /// <summary>
        /// 获取第一个与数组类型属性值
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static object GetArrayPropertyValue(object obj)
        {
            object value = null;

            foreach (PropertyInfo property in obj.GetType().GetProperties())
            {
                if (property.PropertyType.IsArray)
                {
                    value = property.GetValue(obj, null);
                    break;
                }
            }

            return value;
        }

        /// <summary>
        /// 设置某对象指定属性值
        /// </summary>
        /// <param name="obj">数据对象</param>
        /// <param name="propertyName">属性名</param>
        /// <param name="propertyValue">属性值</param>
        public static void SetPropertyValue(object obj, string propertyName, object propertyValue)
        {
            try
            {
                if (obj != null)
                {
                    if (!(propertyValue is DBNull))
                    {
                        PropertyInfo property = obj.GetType().GetProperty(propertyName);
                        if (property != null)
                        {
                            if (propertyValue != null && propertyValue.GetType().Name == "String")
                                propertyValue = propertyValue.ToString().Trim();
                            property.SetValue(obj, propertyValue, null);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Log.WriteLine(LogSeverityType.ERR, C_ModuleName.FRAMEWORK, e);
                throw e;
            }
        }

        /// <summary>
        /// 获取指定对象所有属性
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static PropertyInfo[] GetProperties(object obj)
        {
            return obj.GetType().GetProperties();
        }

        /// <summary>
        /// 获取类类型属性列表
        /// </summary>
        /// <param name="type">类类型</param>
        /// <returns></returns>
        public static PropertyInfo[] GetProperties(Type type)
        {
            return type.GetProperties();
        }

        /// <summary>
        /// 获取类类型属性列表
        /// </summary>
        /// <param name="dllFileName">动态库全名（包含路径）</param>
        /// <param name="className">类全名</param>
        /// <returns></returns>
        public static PropertyInfo[] GetProperties(string dllFileName, string className)
        {
            Type type = GetType(dllFileName, className);

            return GetProperties(type);
        }

        /// <summary>
        /// 获取指定属性列表
        /// </summary>
        /// <param name="type"></param>
        /// <param name="attributeType"></param>
        /// <returns></returns>
        public static PropertyInfo[] GetProperties(Type type, Type attributeType)
        {
            List<PropertyInfo> properties = new List<PropertyInfo>();

            var __properties = GetProperties(type);
            foreach (var __property in __properties)
            {
                if (__property.GetCustomAttributes(attributeType, true).Length == 1)
                {
                    properties.Add(__property);
                }
            }

            return properties.ToArray();
        }

        /// <summary>
        /// 获取指定属性列表
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="attributeType"></param>
        /// <returns></returns>
        public static PropertyInfo[] GetProperties(object obj, Type attributeType)
        {
            return GetProperties(obj.GetType(), attributeType);
        }

        /// <summary>
        /// 获取指定属性的特性
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="propertyName"></param>
        /// <param name="attributeType"></param>
        /// <returns></returns>
        public static T GetPropertyAttribute<T>(object obj, string propertyName) where T : class
        {
            return GetPropertyAttribute<T>(GetProperty(obj, propertyName));
        }

        /// <summary>
        /// 获取属性指定特性
        /// </summary>
        /// <param name="property"></param>
        /// <param name="attributeType"></param>
        /// <returns></returns>
        public static T GetPropertyAttribute<T>(PropertyInfo property) where T : class
        {
            T attribute = null;

            if (property != null)
            {
                object[] attributeArrary = property.GetCustomAttributes(typeof(T), true);
                if (attributeArrary.Length == 1)
                {
                    attribute = attributeArrary[0] as T;
                }
            }

            return attribute;
        }

        /// <summary>
        /// 判断是否包含指定特性
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="propertyName"></param>
        /// <param name="attributeType"></param>
        /// <returns></returns>
        public static bool IsContainAttribute(object obj, string propertyName, Type attributeType)
        {
            bool result = false;
            var property = GetProperty(obj, propertyName);

            if (property != null)
            {
                result = IsContainAttribute(property, attributeType);
            }

            return result;
        }

        /// <summary>
        /// 判断是否包含指定特性
        /// </summary>
        /// <param name="property"></param>
        /// <param name="attributeType"></param>
        /// <returns></returns>
        public static bool IsContainAttribute(PropertyInfo property, Type attributeType)
        {
            return property.GetCustomAttributes(attributeType, true).Length == 1;
        }
        #endregion

        #region Private functions
        /// <summary>
        /// 加载程序集
        /// </summary>
        /// <param name="dllFileName">动态库全名（包含路径）</param>
        /// <returns></returns>
        private static Assembly LoadAssembly(string dllFileName)
        {
            return Assembly.LoadFile(dllFileName);
        }
        #endregion
    }
}
